#ifndef ATL_H
#define ATL_H

/*******************************************************************************
 *
 * Voici la librairie des template du projet ADD, ou ADD Template Library
 *
 ******************************************************************************/

#include <iostream>
#include <functional>

/**
 * Ce template permet de mettre dans un flot de sortie quelconque
 * (cout, debugstream, fichier) une variable quelconque, pour autant
 * que l'opérateur << doit définit pour ce type.
 *
 * Le template possède un pointeur sur un flot, initialisé lors de la
 * construction, et un méthode operator(), qui permet de remplir le
 * flot et de le retourner.
 *
 * @author Johan "Solo" Luisier
 */
template< typename T >
class EcrireElementConteneur : std::unary_function <T,std::ostream&>
{
 public:
  /**
   * Constructeur par défaut, initialise le flot qui sera utilisé.
   *
   * @param os flot de sortie, par défaut cout.
   * @param pref préfixe, est ajouté devant chaque valeur, par défaut
   * chaîne vide.
   * @param suf suffixe, est ajouté à la fin de chaque valeur, apr
   * défaut on ajout une espace.
   */
 EcrireElementConteneur( std::ostream* os = std::cout,
			 const std::string& pref = "",
			 const std::string& suf = " " )
   : flot( os ), prefixe( pref ), suffixe( suf )
  {};
  /**
   * Destructeur. On fait un flush, pour être sûr de tout afficher.
   */
  ~EcrireElementConteneur()
    {
      *flot << std::flush;
    };
  /**
   * Réalise l'affichage (ou le remplissage du fichier) avec la valeur
   * passée en argument.
   *
   * @param type variable qui sera écrite dans le flot.
   * @return le flot de sortie.
   */
  std::ostream& operator()(const T& type) const
    {
      return *flot << prefixe << type << suffixe;
    };
 private:
  /**
   * Pointeur sur le flot utilisé.
   */
  std::ostream* flot;
  /**
   * Est ajouté devant la valeur lors de la sortie sur le flot
   */
  std::string prefixe;
  /**
   * Est ajouté derrière la valeur lors de la sortie sur le flot
   */
  std::string suffixe;
};

/**
 * Ce template permet d'extraire une clé d'un conteneur du type
 * std::map, de manière générique. Le but est de l'utiliser dans une
 * boucle for_each.
 *
 * @author Johan "Solo" Luisier
 */
template< typename Clef, typename Valeur >
struct  ExtraireClef : std::unary_function < std::pair<Clef, Valeur>, Clef>
{
  /**
   * Renvoie la clé d'un élément d'une std::map.
   *
   * @param paire paire associant un élément de type Clef à un élément
   * de type Valeur. Un tel objet peut être un élément d'un conteneur
   * du type std::map.   
   *  @return paire.first, qui est du type Clef et est la clé de
   *  l'élément du conteneur associatif.
   */
  Clef operator()( const std::pair< Clef, Valeur >& paire )
  {
    return paire . first;
  };
};

/**
 * Ce template permet d'extraire une valeur d'un conteneur du type
 * std::map, de manière générique. Le but est de l'utiliser dans une
 * boucle for_each.
 *
 * @author Johan "Solo" Luisier
 */
template< typename Clef, typename Valeur >
struct  ExtraireValeur : std::unary_function < std::pair<Clef, Valeur>, Clef>
{
  /**
   * Renvoie la valeur d'un élément d'une std::map.
   *
   * @param paire paire associant un élément de type Clef à un élément
   * de type Valeur. Un tel objet peut être un élément d'un conteneur
   * du type std::map.
   *  @return paire.second, qui est du type Valeur et est la valeur de
   *  l'élément du conteneur associatif.
   * 
   */
  Clef operator()( const std::pair< Clef, Valeur >& paire )
  {
    return paire . second;
  };
};

#include <fstream>

/**
 * Ce template permet de lire et appliquer de manière générique les
 * niveaux de sortie d'une classe quelconque.
 *
 * @param noms conteneur des noms des niveaux à utiliser pour
 * configurer la classe passée en premier argument.
 *
 * @author Johan "Solo" Luisier
 */
template< class T >
void lireNiveaux(T*, const std::vector< std::string >& noms)
{
  std::string test[13] =
    { "ALL", "MEM", "DEBUG", "LFUNC", "LINFO", "FUNC", "INFO", "BLANK",
      "PROGRESS", "RELEASE", "WARN", "ERR", "OFF" };

  std::ifstream entree;
  entree.open( "CONFIG" );

  if ( entree.fail() )
    {
      size_t loc( noms[0].find( "::" ) );
      std::cerr << "Valeur par défaut appliquée pour "
		<< noms[0].substr( 0, loc ) << std::endl;
      return;
    }

  std::string ligne, level;
  unsigned int i, j, nbrNiveaux( noms.size() );
  size_t loc;

  while( ! entree.eof() )
    {
      getline(entree, ligne);

      if ( ligne == "" ) continue;
      
      for ( i = 0; i < nbrNiveaux; i++ )
	{
	  level = "";
	  loc = ligne.find( noms[i], 0 );
	  if ( loc != string::npos )
	    {
	      j = ligne.size() - 1;
	      while( ligne[j] != ' ' )
		{
		  level = ligne[j] + level;
		  j--;
		}
	       for ( j = 0; j < 13; j++ )
		 {
		   if ( test[j] == level )
		     break;
		   
		 }
	       if ( j != 13 )
		 {
		   T::setLevel( j, i + 1 );
		   debug() << noms[i] << ' ' << level << endreq;
		   break;
		 }
	    }
	}
    }	       
};

#endif // ATL_H
